home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / MOR55SRC.ZIP / MORIA / SOURCE / MORIA4.C < prev    next >
C/C++ Source or Header  |  1992-12-07  |  31KB  |  1,175 lines

  1. /* source/moria4.c: misc code, mainly to handle player commands
  2.  
  3.    Copyright (c) 1989-92 James E. Wilson, Robert A. Koeneke
  4.  
  5.    This software may be copied and distributed for educational, research, and
  6.    not for profit purposes provided that this copyright and statement are
  7.    included in all such copies. */
  8.  
  9. #ifdef __TURBOC__
  10. #include    <stdio.h>
  11. #include    <stdlib.h>
  12. #endif
  13.  
  14. #include "config.h"
  15. #include "constant.h"
  16. #include "types.h"
  17. #include "externs.h"
  18.  
  19. #ifdef USG
  20. #ifndef ATARIST_MWC
  21. #include <string.h>
  22. #endif
  23. #else
  24. #include <strings.h>
  25. #endif
  26.  
  27. #include <ctype.h>
  28.  
  29.  
  30. #if defined(LINT_ARGS)
  31. static int look_ray(int, int, int);
  32. static int look_see(int, int, int *);
  33. static void inven_throw(int, struct inven_type *);
  34. static void facts(struct inven_type *, int *, int *, int *, int *);
  35. static void drop_throw(int, int, struct inven_type *);
  36. static void py_bash(int, int);
  37. #else
  38. static int look_ray();
  39. static int look_see();
  40. #endif
  41.  
  42.  
  43. /* Tunnels through rubble and walls            -RAK-    */
  44. /* Must take into account: secret doors,  special tools          */
  45. void tunnel(dir)
  46. int dir;
  47. {
  48.   register int i, tabil;
  49.   register cave_type *c_ptr;
  50.   register inven_type *i_ptr;
  51.   int y, x;
  52.   monster_type *m_ptr;
  53.   vtype out_val, m_name;
  54. #ifdef ATARIST_MWC
  55.   int32u holder;
  56. #endif
  57.  
  58.   if ((py.flags.confused > 0) &&    /* Confused?         */
  59.       (randint(4) > 1))            /* 75% random movement   */
  60.     dir = randint(9);
  61.   y = char_row;
  62.   x = char_col;
  63.   (void) mmove(dir, &y, &x);
  64.  
  65.   c_ptr = &cave[y][x];
  66.   /* Compute the digging ability of player; based on       */
  67.   /* strength, and type of tool used               */
  68.   tabil = py.stats.use_stat[A_STR];
  69.   i_ptr = &inventory[INVEN_WIELD];
  70.  
  71.   /* Don't let the player tunnel somewhere illegal, this is necessary to
  72.      prevent the player from getting a free attack by trying to tunnel
  73.      somewhere where it has no effect.  */
  74.   if (c_ptr->fval < MIN_CAVE_WALL
  75.       && (c_ptr->tptr == 0 || (t_list[c_ptr->tptr].tval != TV_RUBBLE
  76.                    && t_list[c_ptr->tptr].tval != TV_SECRET_DOOR)))
  77.     {
  78.       if (c_ptr->tptr == 0)
  79.     {
  80.       msg_print ("Tunnel through what?  Empty air?!?");
  81.       free_turn_flag = TRUE;
  82.     }
  83.       else
  84.     {
  85.       msg_print("You can't tunnel through that.");
  86.       free_turn_flag = TRUE;
  87.     }
  88.       return;
  89.     }
  90.  
  91.   if (c_ptr->cptr > 1)
  92.     {
  93.       m_ptr = &m_list[c_ptr->cptr];
  94.       if (m_ptr->ml)
  95.     (void) sprintf (m_name, "The %s", c_list[m_ptr->mptr].name);
  96.       else
  97.     (void) strcpy (m_name, "Something");
  98.       (void) sprintf(out_val, "%s is in your way!", m_name);
  99.       msg_print(out_val);
  100.  
  101.       /* let the player attack the creature */
  102.       if (py.flags.afraid < 1)
  103.     py_attack(y, x);
  104.       else
  105.     msg_print("You are too afraid!");
  106.     }
  107.   else if (i_ptr->tval != TV_NOTHING)
  108.     {
  109. #ifdef ATARIST_MWC
  110.       if ((holder = TR_TUNNEL) & i_ptr->flags)
  111. #else
  112.       if (TR_TUNNEL & i_ptr->flags)
  113. #endif
  114.     tabil += 25 + i_ptr->p1*50;
  115.       else
  116.     {
  117.       tabil += (i_ptr->damage[0]*i_ptr->damage[1]) + i_ptr->tohit
  118.         + i_ptr->todam;
  119.       /* divide by two so that digging without shovel isn't too easy */
  120.       tabil >>= 1;
  121.     }
  122.  
  123.       /* If this weapon is too heavy for the player to wield properly, then
  124.      also make it harder to dig with it.  */
  125.  
  126.       if (weapon_heavy)
  127.     {
  128.       tabil += (py.stats.use_stat[A_STR] * 15) - i_ptr->weight;
  129.       if (tabil < 0)
  130.         tabil = 0;
  131.     }
  132.  
  133.       /* Regular walls; Granite, magma intrusion, quartz vein  */
  134.       /* Don't forget the boundary walls, made of titanium (255)*/
  135.       switch(c_ptr->fval)
  136.     {
  137.     case GRANITE_WALL:
  138.       i = randint(1200) + 80;
  139.       if (twall(y, x, tabil, i))
  140.         msg_print("You have finished the tunnel.");
  141.       else
  142.         count_msg_print("You tunnel into the granite wall.");
  143.       break;
  144.     case MAGMA_WALL:
  145.       i = randint(600) + 10;
  146.       if (twall(y, x, tabil, i))
  147.         msg_print("You have finished the tunnel.");
  148.       else
  149.         count_msg_print("You tunnel into the magma intrusion.");
  150.       break;
  151.     case QUARTZ_WALL:
  152.       i = randint(400) + 10;
  153.       if (twall(y, x, tabil, i))
  154.         msg_print("You have finished the tunnel.");
  155.       else
  156.         count_msg_print("You tunnel into the quartz vein.");
  157.       break;
  158.     case BOUNDARY_WALL:
  159.       msg_print("This seems to be permanent rock.");
  160.       break;
  161.     default:
  162.       /* Is there an object in the way?  (Rubble and secret doors)*/
  163.       if (c_ptr->tptr != 0)
  164.         {
  165.           /* Rubble.     */
  166.           if (t_list[c_ptr->tptr].tval == TV_RUBBLE)
  167.         {
  168.           if (tabil > randint(180))
  169.             {
  170.               (void) delete_object(y, x);
  171.               msg_print("You have removed the rubble.");
  172.               if (randint(10) == 1)
  173.             {
  174.               place_object(y, x);
  175.               if (test_light(y, x))
  176.                 msg_print("You have found something!");
  177.             }
  178.               lite_spot(y, x);
  179.             }
  180.           else
  181.             count_msg_print("You dig in the rubble.");
  182.         }
  183.           /* Secret doors.*/
  184.           else if (t_list[c_ptr->tptr].tval == TV_SECRET_DOOR)
  185.         {
  186.           count_msg_print("You tunnel into the granite wall.");
  187.           search(char_row, char_col, py.misc.srh);
  188.         }
  189.           else
  190.         abort ();
  191.         }
  192.       else
  193.         abort ();
  194.       break;
  195.     }
  196.     }
  197.   else
  198.     msg_print("You dig with your hands, making no progress.");
  199. }
  200.  
  201.  
  202. /* Disarms a trap                    -RAK-    */
  203. void disarm_trap()
  204. {
  205.   int y, x, level, tmp, dir, no_disarm;
  206.   register int tot, i;
  207.   register cave_type *c_ptr;
  208.   register inven_type *i_ptr;
  209.   monster_type *m_ptr;
  210.   vtype m_name, out_val;
  211.  
  212.   y = char_row;
  213.   x = char_col;
  214.   if (get_dir(CNIL, &dir))
  215.     {
  216.       (void) mmove(dir, &y, &x);
  217.       c_ptr = &cave[y][x];
  218.       no_disarm = FALSE;
  219.       if (c_ptr->cptr > 1 && c_ptr->tptr != 0 &&
  220.       (t_list[c_ptr->tptr].tval == TV_VIS_TRAP
  221.        || t_list[c_ptr->tptr].tval == TV_CHEST))
  222.     {
  223.       m_ptr = &m_list[c_ptr->cptr];
  224.       if (m_ptr->ml)
  225.         (void) sprintf (m_name, "The %s", c_list[m_ptr->mptr].name);
  226.       else
  227.         (void) strcpy (m_name, "Something");
  228.       (void) sprintf(out_val, "%s is in your way!", m_name);
  229.       msg_print(out_val);
  230.     }
  231.       else if (c_ptr->tptr != 0)
  232.     {
  233.       tot = py.misc.disarm + 2*todis_adj() + stat_adj(A_INT)
  234.         + (class_level_adj[py.misc.pclass][CLA_DISARM] * py.misc.lev / 3);
  235.       if ((py.flags.blind > 0) || (no_light()))
  236.         tot = tot / 10;
  237.       if (py.flags.confused > 0)
  238.         tot = tot / 10;
  239.       if (py.flags.image > 0)
  240.         tot = tot / 10;
  241.       i_ptr = &t_list[c_ptr->tptr];
  242.       i = i_ptr->tval;
  243.       level = i_ptr->level;
  244.       if (i == TV_VIS_TRAP)            /* Floor trap    */
  245.         {
  246.           if ((tot + 100 - level) > randint(100))
  247.         {
  248.           msg_print("You have disarmed the trap.");
  249.           py.misc.exp += i_ptr->p1;
  250.           (void) delete_object(y, x);
  251.           /* make sure we move onto the trap even if confused */
  252.           tmp = py.flags.confused;
  253.           py.flags.confused = 0;
  254.           move_char(dir, FALSE);
  255.           py.flags.confused = tmp;
  256.           prt_experience();
  257.         }
  258.           /* avoid randint(0) call */
  259.           else if ((tot > 5) && (randint(tot) > 5))
  260.         count_msg_print("You failed to disarm the trap.");
  261.           else
  262.         {
  263.           msg_print("You set the trap off!");
  264.           /* make sure we move onto the trap even if confused */
  265.           tmp = py.flags.confused;
  266.           py.flags.confused = 0;
  267.           move_char(dir, FALSE);
  268.           py.flags.confused += tmp;
  269.         }
  270.         }
  271.       else if (i == TV_CHEST)
  272.         {
  273.           if (!known2_p(i_ptr))
  274.         {
  275.           msg_print("I don't see a trap.");
  276.           free_turn_flag = TRUE;
  277.         }
  278.           else if (CH_TRAPPED & i_ptr->flags)
  279.         {
  280.           if ((tot - level) > randint(100))
  281.             {
  282.               i_ptr->flags &= ~CH_TRAPPED;
  283.               if (CH_LOCKED & i_ptr->flags)
  284.             i_ptr->name2 = SN_LOCKED;
  285.               else
  286.             i_ptr->name2 = SN_DISARMED;
  287.               msg_print("You have disarmed the chest.");
  288.               known2(i_ptr);
  289.               py.misc.exp += level;
  290.               prt_experience();
  291.             }
  292.           else if ((tot > 5) && (randint(tot) > 5))
  293.             count_msg_print("You failed to disarm the chest.");
  294.           else
  295.             {
  296.               msg_print("You set a trap off!");
  297.               known2(i_ptr);
  298.               chest_trap(y, x);
  299.             }
  300.         }
  301.           else
  302.         {
  303.           msg_print("The chest was not trapped.");
  304.           free_turn_flag = TRUE;
  305.         }
  306.         }
  307.       else
  308.         no_disarm = TRUE;
  309.     }
  310.       else
  311.     no_disarm = TRUE;
  312.  
  313.       if (no_disarm)
  314.     {
  315.       msg_print("I do not see anything to disarm there.");
  316.       free_turn_flag = TRUE;
  317.     }
  318.     }
  319. }
  320.  
  321.  
  322. /* An enhanced look, with peripheral vision. Looking all 8    -CJS-
  323.    directions will see everything which ought to be visible. Can
  324.    specify direction 5, which looks in all directions.
  325.  
  326.    For the purpose of hindering vision, each place is regarded as
  327.    a diamond just touching its four immediate neighbours. A
  328.    diamond is opaque if it is a wall, or shut door, or something
  329.    like that. A place is visible if any part of its diamond is
  330.    visible: i.e. there is a line from the view point to part of
  331.    the diamond which does not pass through any opaque diamonds.
  332.  
  333.    Consider the following situation:
  334.  
  335.      @....                X    X   X    X   X
  336.      .##..               / \ / \ / \ / \ / \
  337.      .....              X @ X . X . X 1 X . X
  338.                    \ / \ / \ / \ / \ /
  339.                     X    X   X    X   X
  340.        Expanded view, with       / \ / \ / \ / \ / \
  341.        diamonds inscribed      X . X # X # X 2 X . X
  342.        about each point,       \ / \ / \ / \ / \ /
  343.        and some locations        X    X   X    X   X
  344.        numbered.           / \ / \ / \ / \ / \
  345.                   X . X . X . X 3 X 4 X
  346.                    \ / \ / \ / \ / \ /
  347.                     X    X   X    X   X
  348.     - Location 1 is fully visible.
  349.     - Location 2 is visible, even though partially obscured.
  350.     - Location 3 is invisible, but if either # were
  351.       transparent, it would be visible.
  352.     - Location 4 is completely obscured by a single #.
  353.  
  354.    The function which does the work is look_ray. It sets up its
  355.    own co-ordinate frame (global variables map back to the
  356.    dungeon frame) and looks for everything between two angles
  357.    specified from a central line. It is recursive, and each call
  358.    looks at stuff visible along a line parallel to the center
  359.    line, and a set distance away from it. A diagonal look uses
  360.    more extreme peripheral vision from the closest horizontal and
  361.    vertical directions; horizontal or vertical looks take a call
  362.    for each side of the central line. */
  363.  
  364. /* Globally accessed variables: gl_nseen counts the number of places where
  365.    something is seen. gl_rock indicates a look for rock or objects.
  366.  
  367.    The others map co-ords in the ray frame to dungeon co-ords.
  368.  
  369.    dungeon y = char_row     + gl_fyx * (ray x)  + gl_fyy * (ray y)
  370.    dungeon x = char_col     + gl_fxx * (ray x)  + gl_fxy * (ray y) */
  371. static int gl_fxx, gl_fxy, gl_fyx, gl_fyy;
  372. static int gl_nseen, gl_noquery;
  373. static int gl_rock;
  374. /* Intended to be indexed by dir/2, since is only relevant to horizontal or
  375.    vertical directions. */
  376. static int set_fxy[] = { 0,  1,     0,  0, -1 };
  377. static int set_fxx[] = { 0,  0, -1,  1,     0 };
  378. static int set_fyy[] = { 0,  0,     1, -1,     0 };
  379. static int set_fyx[] = { 0,  1,     0,  0, -1 };
  380. /* Map diagonal-dir/2 to a normal-dir/2. */
  381. static int map_diag1[] = { 1, 3, 0, 2, 4 };
  382. static int map_diag2[] = { 2, 1, 0, 4, 3 };
  383.  
  384. #define GRADF    10000    /* Any sufficiently big number will do */
  385.  
  386. /* Look at what we can see. This is a free move.
  387.  
  388.    Prompts for a direction, and then looks at every object in
  389.    turn within a cone of vision in that direction. For each
  390.    object, the cursor is moved over the object, a description is
  391.    given, and we wait for the user to type something. Typing
  392.    ESCAPE will abort the entire look.
  393.  
  394.    Looks first at real objects and monsters, and looks at rock
  395.    types only after all other things have been seen.  Only looks at rock
  396.    types if the highlight_seams option is set. */
  397.  
  398. void look()
  399. {
  400.   register int i, abort;
  401.   int dir, dummy;
  402.  
  403.   if (py.flags.blind > 0)
  404.     msg_print("You can't see a damn thing!");
  405.   else if (py.flags.image > 0)
  406.     msg_print("You can't believe what you are seeing! It's like a dream!");
  407.   else if (get_alldir("Look which direction?", &dir))
  408.     {
  409.       abort = FALSE;
  410.       gl_nseen = 0;
  411.       gl_rock = 0;
  412.       gl_noquery = FALSE;    /* Have to set this up for the look_see */
  413.       if (look_see(0, 0, &dummy))
  414.     abort = TRUE;
  415.       else
  416.     {
  417.       do
  418.         {
  419.           abort = FALSE;
  420.           if (dir == 5)
  421.         {
  422.           for (i = 1; i <= 4; i++)
  423.             {
  424.               gl_fxx = set_fxx[i]; gl_fyx = set_fyx[i];
  425.               gl_fxy = set_fxy[i]; gl_fyy = set_fyy[i];
  426.               if (look_ray(0, 2*GRADF-1, 1))
  427.             {
  428.               abort = TRUE;
  429.               break;
  430.             }
  431.               gl_fxy = -gl_fxy;
  432.               gl_fyy = -gl_fyy;
  433.               if (look_ray(0, 2*GRADF, 2))
  434.             {
  435.               abort = TRUE;
  436.               break;
  437.             }
  438.             }
  439.         }
  440.           else if ((dir & 1) == 0)    /* Straight directions */
  441.         {
  442.           i = dir >> 1;
  443.           gl_fxx = set_fxx[i]; gl_fyx = set_fyx[i];
  444.           gl_fxy = set_fxy[i]; gl_fyy = set_fyy[i];
  445.           if (look_ray(0, GRADF, 1))
  446.             abort = TRUE;
  447.           else
  448.             {
  449.               gl_fxy = -gl_fxy;
  450.               gl_fyy = -gl_fyy;
  451.               abort = look_ray(0, GRADF, 2);
  452.             }
  453.         }
  454.           else
  455.         {
  456.           i = map_diag1[dir >> 1];
  457.           gl_fxx = set_fxx[i]; gl_fyx = set_fyx[i];
  458.           gl_fxy = -set_fxy[i]; gl_fyy = -set_fyy[i];
  459.           if (look_ray(1, 2*GRADF, GRADF))
  460.             abort = TRUE;
  461.           else
  462.             {
  463.               i = map_diag2[dir >> 1];
  464.               gl_fxx = set_fxx[i]; gl_fyx = set_fyx[i];
  465.               gl_fxy = set_fxy[i]; gl_fyy = set_fyy[i];
  466.               abort = look_ray(1, 2*GRADF-1, GRADF);
  467.             }
  468.         }
  469.         }
  470.       while (abort == FALSE && highlight_seams && (++gl_rock < 2));
  471.       if (abort)
  472.         msg_print("--Aborting look--");
  473.       else
  474.         {
  475.           if (gl_nseen)
  476.         {
  477.           if (dir == 5)
  478.             msg_print("That's all you see.");
  479.           else
  480.             msg_print("That's all you see in that direction.");
  481.         }
  482.           else if (dir == 5)
  483.         msg_print("You see nothing of interest.");
  484.           else
  485.         msg_print("You see nothing of interest in that direction.");
  486.         }
  487.     }
  488.     }
  489. }
  490.  
  491. /* Look at everything within a cone of vision between two ray
  492.    lines emanating from the player, and y or more places away
  493.    from the direct line of view. This is recursive.
  494.  
  495.    Rays are specified by gradients, y over x, multiplied by
  496.    2*GRADF. This is ONLY called with gradients between 2*GRADF
  497.    (45 degrees) and 1 (almost horizontal).
  498.  
  499.    (y axis)/ angle from
  500.      ^      /        ___ angle to
  501.      |     /     ___
  502.   ...|../.....___.................... parameter y (look at things in the
  503.      | /   ___                  cone, and on or above this line)
  504.      |/ ___
  505.      @-------------------->   direction in which you are looking. (x axis)
  506.      |
  507.      | */
  508. static int look_ray(y, from, to)
  509. int y, from, to;
  510. {
  511.   register int max_x, x;
  512.   int transparent;
  513.  
  514.   /* from is the larger angle of the ray, since we scan towards the
  515.      center line. If from is smaller, then the ray does not exist. */
  516.   if (from <= to || y > MAX_SIGHT)
  517.     return FALSE;
  518.   /* Find first visible location along this line. Minimum x such
  519.      that (2x-1)/x < from/GRADF <=> x > GRADF(2x-1)/from. This may
  520.      be called with y=0 whence x will be set to 0. Thus we need a
  521.      special fix. */
  522.   x = (int)((long)GRADF * (2 * y - 1) / from + 1);
  523.   if (x <= 0)
  524.     x = 1;
  525.  
  526.   /* Find last visible location along this line.
  527.      Maximum x such that (2x+1)/x > to/GRADF <=> x < GRADF(2x+1)/to */
  528.   max_x = (int)(((long)GRADF * (2 * y + 1) - 1) / to);
  529.   if (max_x > MAX_SIGHT)
  530.     max_x = MAX_SIGHT;
  531.   if (max_x < x)
  532.     return FALSE;
  533.  
  534.   /* gl_noquery is a HACK to prevent doubling up on direct lines of
  535.      sight. If 'to' is    greater than 1, we do not really look at
  536.      stuff along the direct line of sight, but we do have to see
  537.      what is opaque for the purposes of obscuring other objects. */
  538.   if (y == 0 && to > 1 || y == x && from < GRADF*2)
  539.     gl_noquery = TRUE;
  540.   else
  541.     gl_noquery = FALSE;
  542.   if (look_see(x, y, &transparent))
  543.     return TRUE;
  544.   if (y == x)
  545.     gl_noquery = FALSE;
  546.   if (transparent)
  547.     goto init_transparent;
  548.  
  549.   for (;;)
  550.     {
  551.       /* Look down the window we've found. */
  552.       if (look_ray(y+1, from, (int)((2 * y + 1) * (long)GRADF / x)))
  553.     return TRUE;
  554.       /* Find the start of next window. */
  555.       do
  556.     {
  557.       if (x == max_x)
  558.         return FALSE;
  559.       /* See if this seals off the scan. (If y is zero, then it will.) */
  560.       from = (int)((2 * y - 1) * (long)GRADF / x);
  561.       if (from <= to)
  562.         return FALSE;
  563.       x++;
  564.       if (look_see(x, y, &transparent))
  565.         return TRUE;
  566.     }
  567.       while(!transparent);
  568.     init_transparent:
  569.       /* Find the end of this window of visibility. */
  570.       do
  571.     {
  572.       if (x == max_x)
  573.         /* The window is trimmed by an earlier limit. */
  574.         return look_ray(y+1, from, to);
  575.       x++;
  576.       if (look_see(x, y, &transparent))
  577.         return TRUE;
  578.     }
  579.       while(transparent);
  580.     }
  581. }
  582.  
  583. static int look_see(x, y, transparent)
  584. register int x, y;
  585. int *transparent;
  586. {
  587.   char *dstring, *string, query;
  588.   register cave_type *c_ptr;
  589.   register int j;
  590.   bigvtype out_val, tmp_str;
  591.  
  592.   if (x < 0 || y < 0 || y > x)
  593.     {
  594.       (void) sprintf(tmp_str, "Illegal call to look_see(%d, %d)", x, y);
  595.       msg_print(tmp_str);
  596.     }
  597.   if (x == 0 && y == 0)
  598.     dstring = "You are on";
  599.   else
  600.     dstring = "You see";
  601.   j = char_col + gl_fxx * x + gl_fxy * y;
  602.   y = char_row + gl_fyx * x + gl_fyy * y;
  603.   x = j;
  604.   if (!panel_contains(y, x))
  605.     {
  606.       *transparent = FALSE;
  607.       return FALSE;
  608.     }
  609.   c_ptr = &cave[y][x];
  610.   *transparent = c_ptr->fval <= MAX_OPEN_SPACE;
  611.   if (gl_noquery)
  612.     return FALSE; /* Don't look at a direct line of sight. A hack. */
  613.   out_val[0] = 0;
  614.   if (gl_rock == 0 && c_ptr->cptr > 1 && m_list[c_ptr->cptr].ml)
  615.     {
  616.       j = m_list[c_ptr->cptr].mptr;
  617.       (void) sprintf(out_val, "%s %s %s. [(r)ecall]",
  618.              dstring,
  619.              is_a_vowel( c_list[j].name[0] ) ? "an" : "a",
  620.              c_list[j].name);
  621.       dstring = "It is on";
  622.       prt(out_val, 0, 0);
  623.       move_cursor_relative(y, x);
  624.       query = inkey();
  625.       if (query == 'r' || query == 'R')
  626.     {
  627.       save_screen();
  628.       query = roff_recall(j);
  629.       restore_screen();
  630.     }
  631.     }
  632.   if (c_ptr->tl || c_ptr->pl || c_ptr->fm)
  633.     {
  634.       if (c_ptr->tptr != 0)
  635.     {
  636.       if (t_list[c_ptr->tptr].tval == TV_SECRET_DOOR)
  637.         goto granite;
  638.       if (gl_rock ==0 && t_list[c_ptr->tptr].tval != TV_INVIS_TRAP)
  639.         {
  640.           objdes(tmp_str, &t_list[c_ptr->tptr], TRUE);
  641.           (void) sprintf(out_val, "%s %s ---pause---", dstring, tmp_str);
  642.           dstring = "It is in";
  643.           prt(out_val, 0, 0);
  644.           move_cursor_relative(y, x);
  645.           query = inkey();
  646.         }
  647.     }
  648.       if ((gl_rock || out_val[0]) && c_ptr->fval >= MIN_CLOSED_SPACE)
  649.     {
  650.       switch(c_ptr->fval)
  651.         {
  652.         case BOUNDARY_WALL:
  653.         case GRANITE_WALL:
  654.         granite:
  655.           /* Granite is only interesting if it contains something. */
  656.           if(out_val[0])
  657.         string = "a granite wall";
  658.           else
  659.         string = CNIL;    /* In case we jump here */
  660.           break;
  661.         case MAGMA_WALL: string = "some dark rock";
  662.           break;
  663.         case QUARTZ_WALL: string = "a quartz vein";
  664.           break;
  665.         default: string = CNIL;
  666.           break;
  667.         }
  668.       if (string)
  669.         {
  670.           (void) sprintf(out_val, "%s %s ---pause---", dstring, string);
  671.           prt(out_val, 0, 0);
  672.           move_cursor_relative(y, x);
  673.           query = inkey();
  674.         }
  675.     }
  676.     }
  677.   if (out_val[0])
  678.     {
  679.       gl_nseen++;
  680.       if (query == ESCAPE)
  681.     return TRUE;
  682.     }
  683.  
  684.   return FALSE;
  685. }
  686.  
  687.  
  688. static void inven_throw(item_val, t_ptr)
  689. int item_val;
  690. inven_type *t_ptr;
  691. {
  692.   register inven_type *i_ptr;
  693. #ifdef ATARIST_MWC
  694.   int32u holder;
  695. #endif
  696.  
  697.   i_ptr = &inventory[item_val];
  698.   *t_ptr = *i_ptr;
  699.   if (i_ptr->number > 1)
  700.     {
  701.       t_ptr->number = 1;
  702.       i_ptr->number--;
  703.       inven_weight -= i_ptr->weight;
  704. #ifdef ATARIST_MWC
  705.       py.flags.status |= (holder = PY_STR_WGT);
  706. #else
  707.       py.flags.status |= PY_STR_WGT;
  708. #endif
  709.     }
  710.   else
  711.     inven_destroy(item_val);
  712. }
  713.  
  714.  
  715. /* Obtain the hit and damage bonuses and the maximum distance for a
  716.    thrown missile. */
  717. static void facts(i_ptr, tbth, tpth, tdam, tdis)
  718. register inven_type *i_ptr;
  719. int *tbth, *tpth, *tdam, *tdis;
  720. {
  721.   register int tmp_weight;
  722.  
  723.   if (i_ptr->weight < 1)
  724.     tmp_weight = 1;
  725.   else
  726.     tmp_weight = i_ptr->weight;
  727.  
  728.   /* Throwing objects            */
  729.   *tdam = pdamroll(i_ptr->damage) + i_ptr->todam;
  730.   *tbth = py.misc.bthb * 75 / 100;
  731.   *tpth = py.misc.ptohit + i_ptr->tohit;
  732.  
  733.   /* Add this back later if the correct throwing device. -CJS- */
  734.   if (inventory[INVEN_WIELD].tval != TV_NOTHING)
  735.     *tpth -= inventory[INVEN_WIELD].tohit;
  736.  
  737.   *tdis = (((py.stats.use_stat[A_STR]+20)*10)/tmp_weight);
  738.   if (*tdis > 10)  *tdis = 10;
  739.  
  740.   /* multiply damage bonuses instead of adding, when have proper
  741.      missile/weapon combo, this makes them much more useful */
  742.  
  743.   /* Using Bows,  slings,  or crossbows    */
  744.   if (inventory[INVEN_WIELD].tval == TV_BOW)
  745.     switch(inventory[INVEN_WIELD].p1)
  746.       {
  747.       case 1:
  748.     if (i_ptr->tval == TV_SLING_AMMO) /* Sling and ammo */
  749.       {
  750.         *tbth = py.misc.bthb;
  751.         *tpth += 2 * inventory[INVEN_WIELD].tohit;
  752.         *tdam += inventory[INVEN_WIELD].todam;
  753.         *tdam = *tdam * 2;
  754.         *tdis = 20;
  755.       }
  756.     break;
  757.       case 2:
  758.     if (i_ptr->tval == TV_ARROW)      /* Short Bow and Arrow    */
  759.       {
  760.         *tbth = py.misc.bthb;
  761.         *tpth += 2 * inventory[INVEN_WIELD].tohit;
  762.         *tdam += inventory[INVEN_WIELD].todam;
  763.         *tdam = *tdam * 2;
  764.         *tdis = 25;
  765.       }
  766.     break;
  767.       case 3:
  768.     if (i_ptr->tval == TV_ARROW)      /* Long Bow and Arrow    */
  769.       {
  770.         *tbth = py.misc.bthb;
  771.         *tpth += 2 * inventory[INVEN_WIELD].tohit;
  772.         *tdam += inventory[INVEN_WIELD].todam;
  773.         *tdam = *tdam * 3;
  774.         *tdis = 30;
  775.       }
  776.     break;
  777.       case 4:
  778.     if (i_ptr->tval == TV_ARROW)      /* Composite Bow and Arrow*/
  779.       {
  780.         *tbth = py.misc.bthb;
  781.         *tpth += 2 * inventory[INVEN_WIELD].tohit;
  782.         *tdam += inventory[INVEN_WIELD].todam;
  783.         *tdam = *tdam * 4;
  784.         *tdis = 35;
  785.       }
  786.     break;
  787.       case 5:
  788.     if (i_ptr->tval == TV_BOLT)      /* Light Crossbow and Bolt*/
  789.       {
  790.         *tbth = py.misc.bthb;
  791.         *tpth += 2 * inventory[INVEN_WIELD].tohit;
  792.         *tdam += inventory[INVEN_WIELD].todam;
  793.         *tdam = *tdam * 3;
  794.         *tdis = 25;
  795.       }
  796.     break;
  797.       case 6:
  798.     if (i_ptr->tval == TV_BOLT)      /* Heavy Crossbow and Bolt*/
  799.       {
  800.         *tbth = py.misc.bthb;
  801.         *tpth += 2 * inventory[INVEN_WIELD].tohit;
  802.         *tdam += inventory[INVEN_WIELD].todam;
  803.         *tdam = *tdam * 4;
  804.         *tdis = 35;
  805.       }
  806.     break;
  807.       }
  808. }
  809.  
  810.  
  811. static void drop_throw(y, x, t_ptr)
  812. int y, x;
  813. inven_type *t_ptr;
  814. {
  815.   register int i, j, k;
  816.   int flag, cur_pos;
  817.   bigvtype out_val, tmp_str;
  818.   register cave_type *c_ptr;
  819.  
  820.   flag = FALSE;
  821.   i = y;
  822.   j = x;
  823.   k = 0;
  824.   if (randint(10) > 1)
  825.     {
  826.       do
  827.     {
  828.       if (in_bounds(i, j))
  829.         {
  830.           c_ptr = &cave[i][j];
  831.           if (c_ptr->fval <= MAX_OPEN_SPACE && c_ptr->tptr == 0)
  832.         flag = TRUE;
  833.         }
  834.       if (!flag)
  835.         {
  836.           i = y + randint(3) - 2;
  837.           j = x + randint(3) - 2;
  838.           k++;
  839.         }
  840.     }
  841.       while ((!flag) && (k <= 9));
  842.     }
  843.   if (flag)
  844.     {
  845.       cur_pos = popt();
  846.       cave[i][j].tptr = cur_pos;
  847.       t_list[cur_pos] = *t_ptr;
  848.       lite_spot(i, j);
  849.     }
  850.   else
  851.     {
  852.       objdes(tmp_str, t_ptr, FALSE);
  853.       (void) sprintf(out_val, "The %s disappears.", tmp_str);
  854.       msg_print(out_val);
  855.     }
  856. }
  857.  
  858. /* Throw an object across the dungeon.        -RAK-    */
  859. /* Note: Flasks of oil do fire damage                 */
  860. /* Note: Extra damage and chance of hitting when missiles are used*/
  861. /*     with correct weapon.  I.E.  wield bow and throw arrow.     */
  862. void throw_object()
  863. {
  864.   int item_val, tbth, tpth, tdam, tdis;
  865.   int y, x, oldy, oldx, cur_dis, dir;
  866.   int flag, visible;
  867.   bigvtype out_val, tmp_str;
  868.   inven_type throw_obj;
  869.   register cave_type *c_ptr;
  870.   register monster_type *m_ptr;
  871.   register int i;
  872.   char tchar;
  873.  
  874.   if (inven_ctr == 0)
  875.     {
  876.       msg_print("But you are not carrying anything.");
  877.       free_turn_flag = TRUE;
  878.     }
  879.   else if (get_item(&item_val, "Fire/Throw which one?", 0, inven_ctr-1, CNIL,
  880.             CNIL))
  881.     {
  882.       if (get_dir(CNIL, &dir))
  883.     {
  884.       desc_remain(item_val);
  885.       if (py.flags.confused > 0)
  886.         {
  887.           msg_print("You are confused.");
  888.           do
  889.         {
  890.           dir = randint(9);
  891.         }
  892.           while (dir == 5);
  893.         }
  894.       inven_throw(item_val, &throw_obj);
  895.       facts(&throw_obj, &tbth, &tpth, &tdam, &tdis);
  896.       tchar = throw_obj.tchar;
  897.       flag = FALSE;
  898.       y = char_row;
  899.       x = char_col;
  900.       oldy = char_row;
  901.       oldx = char_col;
  902.       cur_dis = 0;
  903.       do
  904.         {
  905.           (void) mmove(dir, &y, &x);
  906.           cur_dis++;
  907.           lite_spot(oldy, oldx);
  908.           if (cur_dis > tdis)  flag = TRUE;
  909.           c_ptr = &cave[y][x];
  910.           if ((c_ptr->fval <= MAX_OPEN_SPACE) && (!flag))
  911.         {
  912.           if (c_ptr->cptr > 1)
  913.             {
  914.               flag = TRUE;
  915.               m_ptr = &m_list[c_ptr->cptr];
  916.               tbth = tbth - cur_dis;
  917.               /* if monster not lit, make it much more difficult to
  918.              hit, subtract off most bonuses, and reduce bthb
  919.              depending on distance */
  920.               if (!m_ptr->ml)
  921.             tbth = (tbth / (cur_dis+2))
  922.               - (py.misc.lev *
  923.                  class_level_adj[py.misc.pclass][CLA_BTHB] / 2)
  924.                 - (tpth * (BTH_PLUS_ADJ-1));
  925.               if (test_hit(tbth, (int)py.misc.lev, tpth,
  926.                    (int)c_list[m_ptr->mptr].ac, CLA_BTHB))
  927.             {
  928.               i = m_ptr->mptr;
  929.               objdes(tmp_str, &throw_obj, FALSE);
  930.               /* Does the player know what he's fighting?       */
  931.               if (!m_ptr->ml)
  932.                 {
  933.                   (void) sprintf(out_val,
  934.                "You hear a cry as the %s finds a mark.", tmp_str);
  935.                   visible = FALSE;
  936.                 }
  937.               else
  938.                 {
  939.                   (void) sprintf(out_val, "The %s hits the %s.",
  940.                          tmp_str, c_list[i].name);
  941.                   visible = TRUE;
  942.                 }
  943.               msg_print(out_val);
  944.               tdam = tot_dam(&throw_obj, tdam, i);
  945.               tdam = critical_blow((int)throw_obj.weight,
  946.                            tpth, tdam, CLA_BTHB);
  947.               if (tdam < 0) tdam = 0;
  948.               i = mon_take_hit((int)c_ptr->cptr, tdam);
  949.               if (i >= 0)
  950.                 {
  951.                   if (!visible)
  952.                 msg_print("You have killed something!");
  953.                   else
  954.                 {
  955.               (void) sprintf(out_val,"You have killed the %s.",
  956.                          c_list[i].name);
  957.                   msg_print(out_val);
  958.                 }
  959.                   prt_experience();
  960.                 }
  961.             }
  962.               else
  963.             drop_throw(oldy, oldx, &throw_obj);
  964.             }
  965.           else
  966.             {    /* do not test c_ptr->fm here */
  967.               if (panel_contains(y, x) && (py.flags.blind < 1)
  968.               && (c_ptr->tl || c_ptr->pl))
  969.             {
  970.               print(tchar, y, x);
  971.               put_qio(); /* show object moving */
  972.             }
  973.             }
  974.         }
  975.           else
  976.         {
  977.           flag = TRUE;
  978.           drop_throw(oldy, oldx, &throw_obj);
  979.         }
  980.           oldy = y;
  981.           oldx = x;
  982.         }
  983.       while (!flag);
  984.     }
  985.     }
  986. }
  987.  
  988.  
  989. /* Make a bash attack on someone.                -CJS-
  990.    Used to be part of bash above. */
  991. static void py_bash(y, x)
  992. int y, x;
  993. {
  994.   int monster, k, avg_max_hp, base_tohit;
  995.   register creature_type *c_ptr;
  996.   register monster_type *m_ptr;
  997.   vtype m_name, out_val;
  998.  
  999.   monster = cave[y][x].cptr;
  1000.   m_ptr = &m_list[monster];
  1001.   c_ptr = &c_list[m_ptr->mptr];
  1002.   m_ptr->csleep = 0;
  1003.   /* Does the player know what he's fighting?       */
  1004.   if (!m_ptr->ml)
  1005.     (void) strcpy(m_name, "it");
  1006.   else
  1007.     (void) sprintf(m_name, "the %s", c_ptr->name);
  1008.   base_tohit = py.stats.use_stat[A_STR] + inventory[INVEN_ARM].weight/2
  1009.     + py.misc.wt/10;
  1010.   if (!m_ptr->ml)
  1011.     base_tohit = (base_tohit / 2)
  1012.       - (py.stats.use_stat[A_DEX]*(BTH_PLUS_ADJ-1))
  1013.     - (py.misc.lev * class_level_adj[py.misc.pclass][CLA_BTH] / 2);
  1014.  
  1015.   if (test_hit(base_tohit, (int)py.misc.lev,
  1016.            (int)py.stats.use_stat[A_DEX], (int)c_ptr->ac, CLA_BTH))
  1017.     {
  1018.       (void) sprintf(out_val, "You hit %s.", m_name);
  1019.       msg_print(out_val);
  1020.       k = pdamroll(inventory[INVEN_ARM].damage);
  1021.       k = critical_blow((int)(inventory[INVEN_ARM].weight / 4
  1022.                   + py.stats.use_stat[A_STR]), 0, k, CLA_BTH);
  1023.       k += py.misc.wt/60 + 3;
  1024.       if (k < 0) k = 0;
  1025.  
  1026.       /* See if we done it in.                     */
  1027.       if (mon_take_hit(monster, k) >= 0)
  1028.     {
  1029.       (void) sprintf(out_val, "You have slain %s.", m_name);
  1030.       msg_print(out_val);
  1031.       prt_experience();
  1032.     }
  1033.       else
  1034.     {
  1035.       m_name[0] = toupper((int)m_name[0]); /* Capitalize */
  1036.       /* Can not stun Balrog */
  1037.       avg_max_hp = (c_ptr->cdefense & CD_MAX_HP ?
  1038.             c_ptr->hd[0] * c_ptr->hd[1] :
  1039.             (c_ptr->hd[0] * (c_ptr->hd[1] + 1)) >> 1);
  1040.       if ((100 + randint(400) + randint(400))
  1041.           > (m_ptr->hp + avg_max_hp))
  1042.         {
  1043.           m_ptr->stunned += randint(3) + 1;
  1044.           if (m_ptr->stunned > 24)    m_ptr->stunned = 24;
  1045.           (void) sprintf(out_val, "%s appears stunned!", m_name);
  1046.         }
  1047.       else
  1048.         (void) sprintf(out_val, "%s ignores your bash!", m_name);
  1049.       msg_print(out_val);
  1050.     }
  1051.     }
  1052.   else
  1053.     {
  1054.       (void) sprintf(out_val, "You miss %s.", m_name);
  1055.       msg_print(out_val);
  1056.     }
  1057.   if (randint(150) > py.stats.use_stat[A_DEX])
  1058.     {
  1059.       msg_print("You are off balance.");
  1060.       py.flags.paralysis = 1 + randint(2);
  1061.     }
  1062. }
  1063.  
  1064.  
  1065. /* Bash open a door or chest                -RAK-    */
  1066. /* Note: Affected by strength and weight of character
  1067.  
  1068.    For a closed door, p1 is positive if locked; negative if
  1069.    stuck. A disarm spell unlocks and unjams doors!
  1070.  
  1071.    For an open door, p1 is positive for a broken door.
  1072.  
  1073.    A closed door can be opened - harder if locked. Any door might
  1074.    be bashed open (and thereby broken). Bashing a door is
  1075.    (potentially) faster! You move into the door way. To open a
  1076.    stuck door, it must be bashed. A closed door can be jammed
  1077.    (which makes it stuck if previously locked).
  1078.  
  1079.    Creatures can also open doors. A creature with open door
  1080.    ability will (if not in the line of sight) move though a
  1081.    closed or secret door with no changes. If in the line of
  1082.    sight, closed door are openned, & secret door revealed.
  1083.    Whether in the line of sight or not, such a creature may
  1084.    unlock or unstick a door.
  1085.  
  1086.    A creature with no such ability will attempt to bash a
  1087.    non-secret door. */
  1088. void bash()
  1089. {
  1090.   int y, x, dir, tmp;
  1091.   register cave_type *c_ptr;
  1092.   register inven_type *t_ptr;
  1093.  
  1094.   y = char_row;
  1095.   x = char_col;
  1096.   if (get_dir(CNIL, &dir))
  1097.     {
  1098.       if (py.flags.confused > 0)
  1099.     {
  1100.       msg_print("You are confused.");
  1101.       do
  1102.         {
  1103.           dir = randint(9);
  1104.         }
  1105.       while (dir == 5);
  1106.     }
  1107.       (void) mmove(dir, &y, &x);
  1108.       c_ptr = &cave[y][x];
  1109.       if (c_ptr->cptr > 1)
  1110.     {
  1111.       if (py.flags.afraid > 0)
  1112.         msg_print("You are afraid!");
  1113.       else
  1114.         py_bash(y, x);
  1115.     }
  1116.       else if (c_ptr->tptr != 0)
  1117.     {
  1118.       t_ptr = &t_list[c_ptr->tptr];
  1119.       if (t_ptr->tval == TV_CLOSED_DOOR)
  1120.         {
  1121.           count_msg_print("You smash into the door!");
  1122.           tmp = py.stats.use_stat[A_STR] + py.misc.wt / 2;
  1123.           /* Use (roughly) similar method as for monsters. */
  1124.           if (randint(tmp*(20+abs(t_ptr->p1))) < 10*(tmp-abs(t_ptr->p1)))
  1125.         {
  1126.           msg_print("The door crashes open!");
  1127.           invcopy(&t_list[c_ptr->tptr], OBJ_OPEN_DOOR);
  1128.           t_ptr->p1 = 1 - randint(2); /* 50% chance of breaking door */
  1129.           c_ptr->fval = CORR_FLOOR;
  1130.           if (py.flags.confused == 0)
  1131.             move_char(dir, FALSE);
  1132.           else
  1133.             lite_spot(y, x);
  1134.         }
  1135.           else if (randint(150) > py.stats.use_stat[A_DEX])
  1136.         {
  1137.           msg_print("You are off-balance.");
  1138.           py.flags.paralysis = 1 + randint(2);
  1139.         }
  1140.           else if (command_count == 0)
  1141.         msg_print("The door holds firm.");
  1142.         }
  1143.       else if (t_ptr->tval == TV_CHEST)
  1144.         {
  1145.           if (randint(10) == 1)
  1146.         {
  1147.           msg_print("You have destroyed the chest.");
  1148.           msg_print("and its contents!");
  1149.           t_ptr->index = OBJ_RUINED_CHEST;
  1150.           t_ptr->flags = 0;
  1151.         }
  1152.           else if ((CH_LOCKED & t_ptr->flags) && (randint(10) == 1))
  1153.         {
  1154.           msg_print("The lock breaks open!");
  1155.           t_ptr->flags &= ~CH_LOCKED;
  1156.         }
  1157.           else
  1158.         count_msg_print("The chest holds firm.");
  1159.         }
  1160.       else 
  1161.         /* Can't give free turn, or else player could try directions
  1162.            until he found invisible creature */
  1163.         msg_print("You bash it, but nothing interesting happens.");
  1164.     }
  1165.       else
  1166.     {
  1167.       if (c_ptr->fval < MIN_CAVE_WALL)
  1168.         msg_print("You bash at empty space.");
  1169.       else
  1170.         /* same message for wall as for secret door */
  1171.         msg_print("You bash it, but nothing interesting happens.");
  1172.     }
  1173.     }
  1174. }
  1175.